package org.scribe.model;

import org.apache.http.Header;
import org.apache.http.HeaderIterator;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.DefaultHttpClient;
import org.scribe.utils.StreamUtils;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

/**
 * Represents an HTTP Response.
 *
 * @author Pablo Fernandez
 */
public class Response {
    private static final String EMPTY = "";

    private int code;
    private String body;
    private InputStream stream;
    private Map<String, String> headers;
    private static DefaultHttpClient client;

    Response(HttpURLConnection connection) throws IOException {
        if (connection != null) {
            try {
                connection.connect();
                code = connection.getResponseCode();
                headers = parseHeaders(connection);  // OAuth oauth_problem=parameter_absent&oauth_parameters_absent=oauth_consumer_key,oauth_signature_method,oauth_signature,oauth_timestamp,oauth_nonce
                stream = wasSuccessful() ? connection.getInputStream() : connection.getErrorStream();
            } catch (UnknownHostException e) {
                code = 404;
                body = EMPTY;
            }
        }
    }

    public Response(HttpRequestBase req) {
        if (client == null) {
            client = new DefaultHttpClient();
        }
        try {
            HttpResponse resp = client.execute(req);
            StatusLine sl = resp.getStatusLine();
            code = sl.getStatusCode();
            headers = parseHeaders(resp);  // OAuth oauth_problem=parameter_absent&oauth_parameters_absent=oauth_consumer_key,oauth_signature_method,oauth_signature,oauth_timestamp,oauth_nonce
            if(wasSuccessful()){
                stream = resp.getEntity().getContent();
            }
        } catch (IOException e) {
            code = 404;
            body = EMPTY;
        }
    }

    private String parseBodyContents() {
        body = StreamUtils.getStreamContents(getStream());
        return body;
    }

    private Map<String, String> parseHeaders(HttpResponse resp) {
        Map<String, String> headers = new HashMap<String, String>();
        Header[] allHeaders = resp.getAllHeaders();
        for(Header hd : allHeaders){
            headers.put(hd.getName(),hd.getValue());
        }
        return headers;
    }

    private Map<String, String> parseHeaders(HttpURLConnection conn) {
        Map<String, String> headers = new HashMap<String, String>();
        for (String key : conn.getHeaderFields().keySet()) {
            headers.put(key, conn.getHeaderFields().get(key).get(0));
        }
        return headers;
    }

    private boolean wasSuccessful() {
        return getCode() >= 200 && getCode() < 400;
    }

    /**
     * Obtains the HTTP Response body
     *
     * @return response body
     */
    public String getBody() {
        return body != null ? body : parseBodyContents();
    }

    /**
     * Obtains the meaningful stream of the HttpUrlConnection, either inputStream
     * or errorInputStream, depending on the status code
     *
     * @return input stream / error stream
     */
    public InputStream getStream() {
        return stream;
    }

    /**
     * Obtains the HTTP status code
     *
     * @return the status code
     */
    public int getCode() {
        return code;
    }

    /**
     * Obtains a {@link Map} containing the HTTP Response Headers
     *
     * @return headers
     */
    public Map<String, String> getHeaders() {
        return headers;
    }

    /**
     * Obtains a single HTTP Header value, or null if undefined
     *
     * @param name name
     * @return header value or null
     */
    public String getHeader(String name) {
        return headers.get(name);
    }

}